"""
人脸匹配 UI 模块
"""

import plotly.graph_objects as go  # 导入 Plotly库(仪表盘支持)
import streamlit as st
from PIL import Image

from entity.face_types import ValidMetrics

from .api_client import APIClient
from .utils import display_json_result, file_to_base64


class FaceMatchingUI:
    """人脸匹配 UI 组件"""

    def __init__(self, api_client: APIClient):
        """
        初始化人脸匹配 UI

        Args:
            api_client: API 客户端实例
        """
        self.api_client = api_client

    def render_two_faces_matching(self):
        """渲染两张图片人脸匹配 UI"""
        st.markdown(
            '<div class="sub-header">两张图片人脸匹配</div>', unsafe_allow_html=True
        )

        with st.expander("ℹ️ 功能说明", expanded=True):
            st.markdown(
                "上传两张包含人脸的图片，计算它们的相似度，判断是否为同一个人。"
            )

        # 图片上传区域
        col1, col2 = st.columns(2)

        with col1:
            st.markdown('<div class="card">', unsafe_allow_html=True)
            st.markdown("### 源图片")
            source_image = st.file_uploader(
                "上传源图片", type=["jpg", "jpeg", "png"], key="match_img1"
            )
            if source_image:
                img1 = Image.open(source_image)
                st.image(img1, caption="源图片", use_column_width=True)
            st.markdown("</div>", unsafe_allow_html=True)

        with col2:
            st.markdown('<div class="card">', unsafe_allow_html=True)
            st.markdown("### 目标图片")
            target_image = st.file_uploader(
                "上传目标图片", type=["jpg", "jpeg", "png"], key="match_img2"
            )
            if target_image:
                img2 = Image.open(target_image)
                st.image(img2, caption="目标图片", use_column_width=True)
            st.markdown("</div>", unsafe_allow_html=True)

        # 参数设置
        with st.expander("⚙️ 参数设置"):
            metric = st.selectbox("相似度度量方法", ValidMetrics, index=0)
            threshold = st.slider("相似度阈值", 0.0, 1.0, 0.6)

        # 执行按钮
        button_clicked = st.button("🚀 计算相似度", key="match_faces_btn")
        if button_clicked and source_image and target_image:
            with st.spinner("🔍 正在计算相似度..."):
                try:
                    # 准备请求数据
                    img1_base64 = file_to_base64(source_image)
                    img2_base64 = file_to_base64(target_image)

                    # 调用API
                    result = self.api_client.match_two_faces(
                        img1_base64, img2_base64, metric, threshold
                    )

                    # 显示结果
                    match_result = display_json_result(result, "✅ 相似度计算完成！")

                    if match_result:
                        # 创建结果卡片
                        st.markdown('<div class="card">', unsafe_allow_html=True)
                        st.markdown("### 匹配结果")

                        # 获取匹配结果数据
                        similarity = match_result.get("similarity", 0)
                        match_rate = match_result.get("match_rate", 0)
                        is_matched = match_result.get("matched", False)

                        # 显示匹配结果
                        if is_matched:
                            st.success("✅ 人脸匹配成功!")
                        else:
                            error = match_result.get("error")
                            if error:
                                st.error(f"❌ 匹配失败: {error}")
                            else:
                                st.error("❌ 人脸不匹配")

                        # 显示相似度和匹配率
                        col1, col2 = st.columns(2)
                        with col1:
                            st.metric("相似度", f"{similarity:.4f}")
                        with col2:
                            st.metric("匹配率", f"{match_rate:.2f}%")

                        fig = go.Figure(
                            go.Indicator(
                                mode="gauge+number",
                                value=similarity,
                                domain={"x": [0, 1], "y": [0, 1]},
                                title={"text": "相似度"},
                                gauge={
                                    "axis": {"range": [0, 1]},
                                    "bar": {"color": "darkblue"},
                                    "steps": [
                                        {"range": [0, threshold], "color": "lightgray"},
                                        {
                                            "range": [threshold, 1],
                                            "color": "lightgreen",
                                        },
                                    ],
                                    "threshold": {
                                        "line": {"color": "red", "width": 4},
                                        "thickness": 0.75,
                                        "value": threshold,
                                    },
                                },
                            )
                        )
                        st.plotly_chart(fig, use_container_width=True)

                        st.markdown("</div>", unsafe_allow_html=True)
                except Exception as e:
                    st.error(f"请求失败: {str(e)}")
        elif button_clicked:
            st.warning("请上传源图片和目标图片")

    def render_one_to_many_faces_matching(self):
        """渲染一张图片和一张多人脸图片匹配 UI"""
        st.markdown(
            '<div class="sub-header">一张图片和一张多人脸图片匹配</div>',
            unsafe_allow_html=True,
        )

        with st.expander("ℹ️ 功能说明", expanded=True):
            st.markdown(
                "上传一张源图片和一张包含多个人脸的目标图片，判断源图片中的人脸是否出现在目标图片中。"
                "只要目标图片中有一个人脸与源图片相似度高于阈值，就视为匹配成功。"
            )

        # 图片上传区域
        col1, col2 = st.columns(2)

        with col1:
            st.markdown('<div class="card">', unsafe_allow_html=True)
            st.markdown("### 源图片")
            source_image = st.file_uploader(
                "上传源图片（单人脸）",
                type=["jpg", "jpeg", "png"],
                key="one_to_many_img1",
            )
            if source_image:
                img1 = Image.open(source_image)
                st.image(img1, caption="源图片", use_column_width=True)
            st.markdown("</div>", unsafe_allow_html=True)

        with col2:
            st.markdown('<div class="card">', unsafe_allow_html=True)
            st.markdown("### 目标图片")
            target_image = st.file_uploader(
                "上传目标图片（多人脸）",
                type=["jpg", "jpeg", "png"],
                key="one_to_many_img2",
            )
            if target_image:
                img2 = Image.open(target_image)
                st.image(img2, caption="目标图片", use_column_width=True)
            st.markdown("</div>", unsafe_allow_html=True)

        # 参数设置
        with st.expander("⚙️ 参数设置"):
            metric = st.selectbox(
                "相似度度量方法", ValidMetrics, index=0, key="one_to_many_metric"
            )
            threshold = st.slider(
                "相似度阈值", 0.0, 1.0, 0.6, key="one_to_many_threshold"
            )

        # 执行按钮
        button_clicked = st.button("🚀 查找匹配人脸", key="match_one_to_many_btn")
        if button_clicked and source_image and target_image:
            with st.spinner("🔍 正在查找匹配人脸..."):
                try:
                    # 准备请求数据
                    img1_base64 = file_to_base64(source_image)
                    img2_base64 = file_to_base64(target_image)

                    # 调用API
                    result = self.api_client.match_face_to_faces(
                        img1_base64, img2_base64, metric, threshold
                    )

                    # 显示结果
                    match_result = display_json_result(result, "✅ 匹配查找完成！")

                    if match_result:
                        # 创建结果卡片
                        st.markdown('<div class="card">', unsafe_allow_html=True)
                        st.markdown("### 匹配结果")

                        # 获取匹配结果数据
                        is_matched = match_result.get("matched", False)
                        similarity = match_result.get("similarity", 0)
                        match_rate = match_result.get("match_rate", 0)
                        face_count = match_result.get("face_count", 0)

                        # 显示匹配结果
                        if is_matched:
                            st.success("✅ 匹配成功! 在目标图片中找到了相似人脸")
                        else:
                            error = match_result.get("error")
                            if error:
                                st.error(f"❌ 匹配失败: {error}")
                            else:
                                st.error("❌ 未找到匹配的人脸")

                        # 显示相似度和匹配率
                        col1, col2, col3 = st.columns(3)
                        with col1:
                            st.metric("最高相似度", f"{similarity:.4f}")
                        with col2:
                            st.metric("匹配率", f"{match_rate:.2f}%")
                        with col3:
                            st.metric("检测到的人脸数", f"{face_count}")

                        # 显示相似度仪表盘
                        fig = go.Figure(
                            go.Indicator(
                                mode="gauge+number",
                                value=similarity,
                                domain={"x": [0, 1], "y": [0, 1]},
                                title={"text": "最高相似度"},
                                gauge={
                                    "axis": {"range": [0, 1]},
                                    "bar": {"color": "darkblue"},
                                    "steps": [
                                        {"range": [0, threshold], "color": "lightgray"},
                                        {
                                            "range": [threshold, 1],
                                            "color": "lightgreen",
                                        },
                                    ],
                                    "threshold": {
                                        "line": {"color": "red", "width": 4},
                                        "thickness": 0.75,
                                        "value": threshold,
                                    },
                                },
                            )
                        )
                        st.plotly_chart(fig, use_container_width=True)

                        st.markdown("</div>", unsafe_allow_html=True)
                except Exception as e:
                    st.error(f"请求失败: {str(e)}")
        elif button_clicked:
            st.warning("请上传源图片和目标图片")

    def render(self):
        """渲染人脸匹配 UI"""
        st.markdown(
            '<div class="main-header">👥 人脸匹配</div>', unsafe_allow_html=True
        )

        # 创建标签页
        tabs = st.tabs(
            ["两张图片匹配", "一张图片和一张多人图片匹配", "一张图片和多张图片匹配"]
        )

        # 两张图片匹配标签页
        with tabs[0]:
            self.render_two_faces_matching()

        # 一对多匹配标签页
        with tabs[1]:
            self.render_one_to_many_faces_matching()

        # 多对多匹配标签页
        with tabs[2]:
            st.info("一张图片和多张图片匹配功能正在开发中...")
